package com.jbp.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jbp.dao.SkillOrderDao;
import com.jbp.exception.RRException;
import com.jbp.job.CancelTimeoutOrderJob;
import com.jbp.model.*;
import com.jbp.service.*;
import com.jbp.utils.StrToMillsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jbp.utils.PageUtils;
import com.jbp.utils.Query;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * 技能订单(SkillOrder)表服务实现类
 * @author cc
 * @since 2020-11-28 17:49:31
 */
@Service
public class SkillOrderServiceImpl extends ServiceImpl<SkillOrderDao, SkillOrder> implements SkillOrderService {
    private static final Logger logger = LoggerFactory.getLogger(SkillOrderServiceImpl.class);

    @Autowired
    private SkillUserService skillUserService;
    @Autowired
    private SkillUserParamService skillUserParamService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private WalletRecordService walletRecordService;
    @Autowired
    private UserService userService;
    @Autowired
    private SkillService skillService;
    @Autowired
    private SkillOrderCommentService skillOrderCommentService;
    @Autowired
    private TecentMsgService tecentMsgService;
    @Autowired
    private UserLevelService userLevelService;
    @Override
    @Transactional
    public SkillOrder create(SkillOrder skillOrder, Integer userId) {
        SkillUser skillUser = skillUserService.getById(skillOrder.getSkillUserId());
        if (skillUser==null) {
            throw new RRException("参数错误");
        }
        if (userId.equals(skillUser.getUserId())) {
            throw new RRException("不能给自己下单");
        }
        SkillUserParam priceParam = skillUserParamService.getOne(new QueryWrapper<SkillUserParam>()
                .eq("skill_user_id", skillOrder.getSkillUserId())
                .eq("param_name", "接单价格")
        );
        if (priceParam==null) {
            throw new RRException("价格错误");
        }
        //生成订单号
        String orderNo = "nn"+ StrToMillsUtil.millsToStrDate(new Date(), "yyyyMMddhhmmss")+(new Random().nextInt(8999)+1000);

        BigDecimal price = BigDecimal.valueOf(Double.parseDouble(priceParam.getParamValue()));
        BigDecimal totalPrice = price.multiply(BigDecimal.valueOf(skillOrder.getTimes()));

        skillOrder.setOrderNo(orderNo);
        skillOrder.setServerPrice(price);
        skillOrder.setTotalPrice(totalPrice);
        skillOrder.setCustomerId(userId);
        skillOrder.setGodId(skillUser.getUserId());
        skillOrder.setSkillId(skillUser.getSkillId());
        skillOrder.setStatus(0);
        save(skillOrder);

        sendOrderMsg(skillOrder.getCustomerId(), skillOrder.getGodId(), skillOrder.getId());

        return skillOrder;
    }

    @Override
    public PageUtils buyList(Map<String, Object> params, Integer userId) {
        QueryWrapper<SkillOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("customer_id" , userId);
        queryWrapper.orderByDesc("update_time");
        IPage<SkillOrder> page = this.page(
                new Query<SkillOrder>().getPage(params),
                queryWrapper
        );
        for (SkillOrder skillOrder : page.getRecords()) {
            User god = userService.getById(skillOrder.getGodId());
            skillOrder.setGodName(god.getName());
            skillOrder.setGodImg(god.getImg());
            skillOrder.setGodLevel(god.getLevel());
            skillOrder.setGodLevelOn(userLevelService.levelOn(god.getId()));
            skillOrder.setGodSex(god.getSex());

            Skill skill = skillService.getById(skillOrder.getSkillId());
            skillOrder.setSkillName(skill.getName());

            int commentSize = skillOrderCommentService.count(new QueryWrapper<SkillOrderComment>()
                    .eq("skill_order_id", skillOrder.getId())
                    .eq("skill_user_id", skillOrder.getSkillUserId())
                    .eq("customer_id", skillOrder.getCustomerId())
            );
            skillOrder.setCommented(commentSize>0);
        }

        return new PageUtils(page);
    }

    @Override
    public PageUtils sellList(Map<String, Object> params, Integer userId) {
        QueryWrapper<SkillOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("god_id" , userId);
        queryWrapper.orderByDesc("update_time");
        IPage<SkillOrder> page = this.page(
                new Query<SkillOrder>().getPage(params),
                queryWrapper
        );

        for (SkillOrder skillOrder : page.getRecords()) {
            User customer = userService.getById(skillOrder.getCustomerId());
            skillOrder.setCustomerName(customer.getName());
            skillOrder.setCustomerImg(customer.getImg());
            skillOrder.setCustomerLevel(customer.getLevel());
            skillOrder.setCustomerLevelOn(userLevelService.levelOn(customer.getId()));
            skillOrder.setCustomerSex(customer.getSex());

            Skill skill = skillService.getById(skillOrder.getSkillId());
            skillOrder.setSkillName(skill.getName());
        }

        return new PageUtils(page);
    }


    @Override
    @Transactional
    public void complete(SkillOrder req, Integer userId) {
        SkillOrder skillOrder = getById(req.getId());
        if (skillOrder==null) {
            throw new RRException("订单不存在");
        }
        if(!userId.equals(skillOrder.getCustomerId())) {
            throw new RRException("客户才能完成订单");
        }
        if (skillOrder.getStatus()!=3) {
            throw new RRException("订单状态错误");
        }
        skillOrder.setStatus(4);
        updateById(skillOrder);

        //大神加帐
        BigDecimal totalPrice = skillOrder.getTotalPrice();
        Wallet wallet = walletService.getByUserId(skillOrder.getGodId());

        BigDecimal afterBalance = wallet.getXinzuan().add(totalPrice.multiply(BigDecimal.valueOf(0.8d)));
        WalletRecord walletRecord = new WalletRecord();
        walletRecord.setUserId(userId);
        walletRecord.setCoinType("xinzuan");
        walletRecord.setAddType("add");
        walletRecord.setOperationType("skillin");
        walletRecord.setBeforeBalance(wallet.getXinzuan());
        walletRecord.setChangeBalance(totalPrice);
        walletRecord.setAfterBalance(afterBalance);
        walletRecordService.save(walletRecord);

        wallet.setXinzuan(afterBalance);
        walletService.updateWithLock(wallet);

        sendOrderMsg(skillOrder.getCustomerId(), skillOrder.getGodId(), skillOrder.getId());
    }

    @Override
    public void confirm(SkillOrder req, Integer userId) {
        SkillOrder skillOrder = getById(req.getId());
        if (skillOrder==null) {
            throw new RRException("订单不存在");
        }
        if(!userId.equals(skillOrder.getGodId())) {
            throw new RRException("大神才能确认订单");
        }
        if (skillOrder.getStatus()!=1) {
            throw new RRException("订单状态错误");
        }
        skillOrder.setStatus(2);
        updateById(skillOrder);

        sendOrderMsg( skillOrder.getGodId(), skillOrder.getCustomerId(), skillOrder.getId());
    }

    @Override
    public void start(SkillOrder req, Integer userId) {
        SkillOrder skillOrder = getById(req.getId());
        if (skillOrder==null) {
            throw new RRException("订单不存在");
        }
        if(!userId.equals(skillOrder.getGodId())) {
            throw new RRException("大神才能开始");
        }
        if (skillOrder.getStatus()!=2) {
            throw new RRException("订单状态错误");
        }
        skillOrder.setStatus(3);
        updateById(skillOrder);
        sendOrderMsg( skillOrder.getGodId(), skillOrder.getCustomerId(), skillOrder.getId());
    }

    @Override
    @Transactional
    public void cancle(SkillOrder req, Integer userId) {
        SkillOrder skillOrder = getById(req.getId());
        if (skillOrder==null) {
            throw new RRException("订单不存在");
        }
        if(!userId.equals(skillOrder.getCustomerId()) && !userId.equals(skillOrder.getGodId())) {
            throw new RRException("用户错误");
        }
        boolean skillout = false;

        if (skillOrder.getStatus()==0) {
            //创建 未支付
            skillOrder.setStatus(5);
        } else if (skillOrder.getStatus()==1 || skillOrder.getStatus()==2
                || (userId.equals(skillOrder.getGodId()) && skillOrder.getStatus()==3)) {
            //已支付 退款
            skillout = true;
            skillOrder.setStatus(5);
        }

        updateById(skillOrder);
        if (skillout) {
            BigDecimal totalPrice = skillOrder.getTotalPrice();
            Wallet wallet = walletService.getByUserId(userId);

            BigDecimal afterBalance = wallet.getXinzuan().add(totalPrice);
            WalletRecord walletRecord = new WalletRecord();
            walletRecord.setUserId(userId);
            walletRecord.setCoinType("xinzuan");
            walletRecord.setAddType("add");
            walletRecord.setOperationType("skillrefund");
            walletRecord.setBeforeBalance(wallet.getXinzuan());
            walletRecord.setChangeBalance(totalPrice);
            walletRecord.setAfterBalance(afterBalance);
            walletRecordService.save(walletRecord);

            wallet.setXinzuan(afterBalance);
            walletService.updateWithLock(wallet);
        }

        if (userId.equals(skillOrder.getCustomerId())) {
            sendOrderMsg( skillOrder.getCustomerId(), skillOrder.getGodId  (), skillOrder.getId());
        } else {
            sendOrderMsg( skillOrder.getGodId(), skillOrder.getCustomerId(), skillOrder.getId());
        }
    }

    @Override
    public SkillOrder detail(Integer skillOrderId) {
        SkillOrder skillOrder = getById(skillOrderId);
        User god = userService.getById(skillOrder.getGodId());
        skillOrder.setGodName(god.getName());
        skillOrder.setGodImg(god.getImg());
        skillOrder.setGodLevel(god.getLevel());
        skillOrder.setGodLevelOn(userLevelService.levelOn(god.getId()));
        skillOrder.setGodSex(god.getSex());

        User customer = userService.getById(skillOrder.getCustomerId());
        skillOrder.setCustomerName(customer.getName());
        skillOrder.setCustomerImg(customer.getImg());
        skillOrder.setCustomerLevel(customer.getLevel());
        skillOrder.setCustomerLevelOn(userLevelService.levelOn(customer.getId()));
        skillOrder.setCustomerSex(customer.getSex());

        Skill skill = skillService.getById(skillOrder.getSkillId());
        skillOrder.setSkillName(skill.getName());

        int commentSize = skillOrderCommentService.count(new QueryWrapper<SkillOrderComment>()
                .eq("skill_order_id", skillOrder.getId())
                .eq("skill_user_id", skillOrder.getSkillUserId())
                .eq("customer_id", skillOrder.getCustomerId())
        );
        skillOrder.setCommented(commentSize>0);

        return skillOrder;
    }

    /**发送订单消息*/
    public void sendOrderMsg(Integer fromUserId, Integer toUserId, Integer orderId){
        SkillOrder detail = detail(orderId);
        String message= JSON.toJSONString(detail);
        tecentMsgService.sendMsg(fromUserId.toString(), toUserId.toString(), message, "order");
    }

    @Override
    public List<SkillOrder> goingOrder(Integer otherId, Integer userId) {
        //我是用户
        List<SkillOrder> list = list(new QueryWrapper<SkillOrder>()
                .eq("customer_id", userId)
                .eq("god_id", otherId)
                .in("status", 0, 1, 2,3,4)
                .orderByDesc("update_time")
        );
        List<SkillOrder> list2 = list(new QueryWrapper<SkillOrder>()
                .eq("god_id", userId)
                .eq("customer_id", otherId)
                .in("status", 0, 1, 2,3,4)
                .orderByDesc("update_time")
        );
        if (list!=null) {
            list.addAll(list2);
        }

        for (SkillOrder skillOrder : list) {
            User god = userService.getById(skillOrder.getGodId());
            skillOrder.setGodName(god.getName());
            skillOrder.setGodImg(god.getImg());
            skillOrder.setGodLevel(god.getLevel());
            skillOrder.setGodLevelOn(userLevelService.levelOn(god.getId()));
            skillOrder.setGodSex(god.getSex());

            User customer = userService.getById(skillOrder.getCustomerId());
            skillOrder.setCustomerName(customer.getName());
            skillOrder.setCustomerImg(customer.getImg());
            skillOrder.setCustomerLevel(customer.getLevel());
            skillOrder.setCustomerLevelOn(userLevelService.levelOn(customer.getId()));
            skillOrder.setCustomerSex(customer.getSex());

            Skill skill = skillService.getById(skillOrder.getSkillId());
            skillOrder.setSkillName(skill.getName());

            int commentSize = skillOrderCommentService.count(new QueryWrapper<SkillOrderComment>()
                    .eq("skill_order_id", skillOrder.getId())
                    .eq("skill_user_id", skillOrder.getSkillUserId())
                    .eq("customer_id", skillOrder.getCustomerId())
            );
            skillOrder.setCommented(commentSize>0);
        }

        return list;
    }

    @Override
    public void pay(SkillOrder req, Integer userId) {
        SkillOrder skillOrder = getById(req.getId());
        if (skillOrder.getStatus()!=0) {
            throw new RRException("订单状态错误");
        }
        //扣钱
        Wallet wallet = walletService.getByUserId(userId);
        if (wallet.getXinzuan().compareTo(skillOrder.getTotalPrice())<0) {
            throw new RRException("余额不足");
        }
        BigDecimal afterBalance = wallet.getXinzuan().subtract(skillOrder.getTotalPrice());
        WalletRecord walletRecord = new WalletRecord();
        walletRecord.setUserId(userId);
        walletRecord.setCoinType("xinzuan");
        walletRecord.setAddType("sub");
        walletRecord.setOperationType("skillout");
        walletRecord.setBeforeBalance(wallet.getXinzuan());
        walletRecord.setChangeBalance(skillOrder.getTotalPrice());
        walletRecord.setAfterBalance(afterBalance);
        walletRecordService.save(walletRecord);

        wallet.setXinzuan(afterBalance);
        walletService.updateWithLock(wallet);

        skillOrder.setStatus(1);
        // 设置支付时间，在超时取消订单逻辑里面，会使用到支付时间payTime字段
        skillOrder.setPayTime(new Date());
        updateById(skillOrder);

        sendOrderMsg(skillOrder.getCustomerId(), skillOrder.getGodId(), skillOrder.getId());
    }

    @Override
    @Transactional
    public void timeoutCancel(Integer skillOrderId, Integer origionStatus) {
        // 测试订单状态变化后，抛异常，而不是继续取消订单。在休眠的这段时间，修改数据库中的状态值
        //try {
        //    Thread.sleep(30 * 1000);
        //} catch (InterruptedException e) {
        //    e.printStackTrace();
        //}

        SkillOrder skillOrder = getById(skillOrderId);

        if (skillOrder==null) {
            throw new RRException("订单不存在");
        }

        // 为了避免在处理这些超时订单的过程中，有些订单被支付或者接单了，造成异常，所以需要校验订单的状态是否发生了变化。
        // 比如：订单状态从0变成1（如果还是按照createTime比较就有问题）、订单状态从1变成2（此时不属于待取消的订单了）

        if (origionStatus != skillOrder.getStatus()) {
            String msg = String.format("在处理订单过程中，订单的状态发生了变化，停止取消订单，订单id：%s", skillOrderId);
            throw  new RuntimeException(msg);
        }

        Integer userId = skillOrder.getCustomerId();

        boolean skillout = false;

        if (skillOrder.getStatus()==0) {
            //创建 未支付
            skillOrder.setStatus(6);
        } else if (skillOrder.getStatus()==1 || skillOrder.getStatus()==2
                || (userId.equals(skillOrder.getGodId()) && skillOrder.getStatus()==3)) {
            //已支付 退款
            skillout = true;
            skillOrder.setStatus(6);
        }

        skillOrder.setCancelTime(new Date());
        updateById(skillOrder);
        if (skillout) {
            BigDecimal totalPrice = skillOrder.getTotalPrice();
            Wallet wallet = walletService.getByUserId(userId);
            logger.debug("user {}, balance before refund: {}, refundCount: {}", userId, wallet.getXinzuan(), totalPrice);
            BigDecimal afterBalance = wallet.getXinzuan().add(totalPrice);
            WalletRecord walletRecord = new WalletRecord();
            walletRecord.setUserId(userId);
            walletRecord.setCoinType("xinzuan");
            walletRecord.setAddType("add");
            walletRecord.setOperationType("skillrefund");
            walletRecord.setBeforeBalance(wallet.getXinzuan());
            walletRecord.setChangeBalance(totalPrice);
            walletRecord.setAfterBalance(afterBalance);
            walletRecordService.save(walletRecord);
            logger.debug("user {}, after refund balance: {}", userId, afterBalance);
            wallet.setXinzuan(afterBalance);
            walletService.updateWithLock(wallet);
        }

    }
}
